package yolorpc.fault.tolerant;

import lombok.extern.slf4j.Slf4j;
import yolorpc.RpcApplication;
import yolorpc.config.RpcConfig;
import yolorpc.fault.retry.RetryStrategy;
import yolorpc.fault.retry.RetryStrategyFactory;
import yolorpc.model.RpcRequest;
import yolorpc.model.RpcResponse;
import yolorpc.model.ServiceMetaInfo;
import yolorpc.server.tcp.VertxTcpClient;

import javax.management.relation.RelationNotFoundException;
import java.util.List;
import java.util.Map;

/**
 * 转移到其他服务节点 - 容错策略
 */
@Slf4j
public class FailOverTolerantStrategy implements TolerantStrategy {

    @Override
    public RpcResponse doTolerant(Map<String, Object> context, Exception e) {
        // 通过上下文获取请求内容
        RpcRequest rpcRequest = (RpcRequest) context.getOrDefault("rpcRequest", null);
        if (rpcRequest == null){
            log.info("======触发容错，返回上下文为空======");
            throw new RuntimeException(e.getMessage());
        }
        // 从context中获取serviceMateInfoList
        List<ServiceMetaInfo> serviceMateInfoList = (List<ServiceMetaInfo>) context.getOrDefault("serviceMateInfoList", null);
        if (serviceMateInfoList == null){
            log.info("======serviceMateInfoList获取失败");
            throw new RuntimeException(e);
        }
        RpcResponse rpcResponse = new RpcResponse();
        RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(RpcApplication.getRpcConfig().getRetryStrategy());
        try {
            rpcResponse = retryStrategy.doRetry(() ->
                    VertxTcpClient.doRequest(rpcRequest, serviceMateInfoList.get(0))
            );
        } catch (Exception ex) {
            try {
                serviceMateInfoList.remove(0);
            } catch (Exception exc) {
                throw new RuntimeException(exc);
            }
        }
        return rpcResponse;
    }
}
